#include "CH58x_common.h"
#include "zqm_global.h"
#include "zqm_module.h"
#include "hal_mcu.h"
#include "hal_adc.h"
#include "hal_pow_meter.h"
#include "task_console.h"
#include "task_gather.h"
#include "task_ctrl.h"

// 基于<<传感器连线（8000002941）规格书>> [-40, +105]共计146项, -40 -- 62670 om; 0 -- 6495 om; 40 -- 1071 om; 105 -- 122
// Modified by Kaygle -- 2024-04-02 -- 客户修改阻值表，增加低温到-50, [-50, +105]共计156项
static const unsigned int tem_om_table[] = {
	121000, 113100, 105700, 98870, 92520, 86610, 81120, 76000, 71240, 66810,
	62670, 58818, 55225, 51871, 48740, 45815, 43082, 40527, 38138, 35902,
	33810, 31851, 30016, 28296, 26684, 25172, 23754, 22424, 21175, 20002,
	18900, 17865, 16892, 15976, 15116, 14306, 13544, 12826, 12150, 11513,
	10913, 10347, 9814, 9311, 8836, 8388, 7965, 7566, 7189, 6832,
	6495, 6175, 5872, 5586, 5316, 5060, 4818, 4589, 4372, 4167,
	3973, 3788, 3614, 3448, 3291, 3142, 3000, 2866, 2738, 2617,
	2502, 2392, 2288, 2189, 2095, 2005, 1920, 1838, 1761, 1687,
	1617, 1550, 1486, 1425, 1367, 1312, 1259, 1209, 1161, 1115,
	1071, 1029, 989, 950, 914, 879, 845, 813, 783, 753,
	725, 698, 673, 648, 624, 602, 580, 559, 539, 520,
	502, 484, 467, 451, 436, 421, 406, 392, 379, 367,
	354, 343, 331, 320, 310, 300, 290, 281, 273, 264,
	256, 248, 241, 233, 226, 219, 213, 206, 200, 194,
	189, 183, 178, 173, 167, 163, 158, 154, 149, 145,
	141, 137, 133, 129, 126, 122, };

// 设置传感器故障
static void SetTemSensorErr(void)
{
	zy_st.m_temp = zy_st.d_temp = ZY_TEM_INVALID;
	AdcResetNtc1();
	// 传感器故障报警
	zy_st.alarm |= ZQ_ALARM_SENSOR;
}
short GetMeasureTem(void)
{
	// Modified by Kaygle -- 2024-01-18 -- 硬件对付EMC加了电容, 导致侦测电压到位会延迟, 加延时侦测
	#define TEM_DELAY_CNT 2
	static int delay_cnt = 0;
	int mv = 0, om = 0x7fffffff, ref = 3300;
	// get ntc1 value
	mv = AdcGetNtc1();
	if(zy_st.m_temp == ZY_TEM_INVALID) { // 如果上次传感器已经报错, 容错10mv再恢复, 防止反复跳动
		if( mv > 3190 || mv < 43) {// 继续判断传感器错误, 大概100Ω左右	
			delay_cnt = TEM_DELAY_CNT;		// 恢复时要延迟n个TASK_PERIOD
			SetTemSensorErr();
			return zy_st.m_temp;
		}
		else if(delay_cnt > 0) { // 延时等待, 硬件对付EMC加了电容, 导致侦测电压到位会延迟, 加延时侦测
			delay_cnt--;
			SetTemSensorErr();
			return zy_st.m_temp;
		}
	}
	else if( mv > 3200 || mv < 33 ) {	// 判断传感器错误, mv = 33大概100Ω左右
		delay_cnt = TEM_DELAY_CNT;		// 恢复时要延迟n个TASK_PERIOD
		SetTemSensorErr();
		return zy_st.m_temp;
	}
	ref = AdcGetRef();
	// 换算到阻值
	om = ADC_OM_BASE_DEF * mv / (ref - mv);
	// 查表换算到温度
	int i = 0, n = sizeof(tem_om_table) / sizeof(tem_om_table[0]);
	for (; i < n; i++)
		if (om >= tem_om_table[i]) break;

	if (i == 0) zy_st.m_temp = -50*10;			// 表格下限 到-50
	else if(i >= n) zy_st.m_temp = 105*10;		// 表格上限 到105
	else zy_st.m_temp = 10 * (i - 50) - (100 * (om - tem_om_table[i]) / (tem_om_table[i - 1] - tem_om_table[i]) + 5) / 10; // 除法部分为了保证精度（不使用浮点）, 扩大100倍计算, +5是为了四舍五入, 最后*10是保留小数点一位, x10存储
	if(zy_st.m_temp > 990) zy_st.m_temp = 990;	// 高温侦测不超过99℃
	// 解除传感器故障报警
	short TS = TcGetTS();
	zy_st.alarm &= (~ZQ_ALARM_SENSOR);
	if (zy_st.temp_reach_region == 0 && zy_st.m_temp >= (TS - 20) && zy_st.m_temp <= (TS + 20)) // 温度到达过TS+-2℃区间
		zy_st.temp_reach_region = 1;
	return zy_st.m_temp;
}
// 设置化霜温度传感器故障
static void SetDefrostSensorErr(void)
{
	zy_st.defrost_m_temp = zy_st.defrost_d_temp = ZY_TEM_INVALID;
	AdcResetNtc2();
	// 传感器故障报警
	zy_st.alarm |= ZQ_ALARM_DEFROST_SENSOR;
}
short GetDefrostMeasureTem(void)
{
#if(ZQ_FUNC_ACTIVE_DEFROST == 1) // NTC2 有效
	// Modified by Kaygle -- 2024-01-18 -- 硬件对付EMC加了电容, 导致侦测电压到位会延迟, 加延时侦测
#define TEM_DELAY_CNT 2
	static int delay_cnt = 0;
	int mv = 0, om = 0x7fffffff, ref = 3300;
	// get ntc1 value
	mv = AdcGetNtc2();
	if (zy_st.defrost_m_temp == ZY_TEM_INVALID) { // 如果上次传感器已经报错, 容错10mv再恢复, 防止反复跳动
		if (mv > 3190 || mv < 43) {// 继续判断传感器错误, 大概100Ω左右	
			delay_cnt = TEM_DELAY_CNT;		// 恢复时要延迟n个TASK_PERIOD
			SetDefrostSensorErr();
			return zy_st.defrost_m_temp;
		}
		else if (delay_cnt > 0) { // 延时等待, 硬件对付EMC加了电容, 导致侦测电压到位会延迟, 加延时侦测
			delay_cnt--;
			SetDefrostSensorErr();
			return zy_st.defrost_m_temp;
		}
	}
	else if (mv > 3200 || mv < 33) {	// 判断传感器错误, mv = 33大概100Ω左右
		delay_cnt = TEM_DELAY_CNT;		// 恢复时要延迟n个TASK_PERIOD
		SetDefrostSensorErr();
		return zy_st.defrost_m_temp;
	}
	ref = AdcGetRef();
	// 换算到阻值
	om = ADC_OM_BASE_DEF * mv / (ref - mv);
	// 查表换算到温度
	int i = 0, n = sizeof(tem_om_table) / sizeof(tem_om_table[0]);
	for (; i < n; i++)
		if (om >= tem_om_table[i]) break;

	if (i == 0) zy_st.defrost_m_temp = -50 * 10;			// 表格下限 到-40
	else if (i >= n) zy_st.defrost_m_temp = 105 * 10;		// 表格上限 到105
	else zy_st.defrost_m_temp = 10 * (i - 50) - (100 * (om - tem_om_table[i]) / (tem_om_table[i - 1] - tem_om_table[i]) + 5) / 10; // 除法部分为了保证精度（不使用浮点）, 扩大100倍计算, +5是为了四舍五入, 最后*10是保留小数点一位, x10存储
	if (zy_st.defrost_m_temp > 990) zy_st.defrost_m_temp = 990;	// 高温侦测不超过99℃
	// 解除化霜传感器故障报警
	zy_st.alarm &= (~ZQ_ALARM_DEFROST_SENSOR);
#endif // NTC2 有效
	return zy_st.defrost_m_temp;
}
//short GetMeasureVBat(void)
//{
//	if (zy_st.vbat == NUM_INVALID_WORD) // 电池不存在
//		return zy_st.vbat;
//	else
//		return (short)(AdcGetVBat() * (147 + 510) / 510);
//}

static void TpUpdateHumanCountState()
{
	static int last_state = 0;
	static int h_count = 0;
	static int l_count = 0;
	static int sleep_timer = 0;

	//static int h_count = 0, l_count = 0;
	if(zq_timer_50ms == 0) sleep_timer = h_count = l_count = last_state = 0; // init
	int new_state = GPIOReadHumanSensor();

	if (zq_timer_50ms < 9000) return;	// 红外芯片上电似乎10秒才初始化完毕，10秒左右有一次异常高-低电平变化, 这里设置9s+自检2s

	sleep_timer+=50;
	if (sleep_timer < 4000) return;	// 4s refractory period

	if (!new_state && last_state) {
		zy_st.humman++;
		sleep_timer = 0;
		ZQLOG("detect human %d", zy_st.humman);
	}
	last_state = new_state;
}
// 门状态和计数 50ms采样一次, 50ms内的完成（开+关）会被忽略, 能捕捉到50ms开门, 但是开门计时会有1s误差
static void TpUpdateDoorState(int span_s)
{
	int new_st = GPIOReadDoorState();
	if (new_st) {
		zy_st.door1_timer += (zy_st.door1_timer == 0) ? 1 : span_s;
	}
	else {
		if (zy_st.door1_timer != 0) zy_st.door1_count++; 
		zy_st.door1_timer = 0;
	}
	// 门开报警,5分钟
	if (zy_st.door1_timer > 5 * 60)
		zy_st.alarm |= ZQ_ALARM_DOOR_OPEN;
	else
		zy_st.alarm &= (~ZQ_ALARM_DOOR_OPEN);
}
// 系统开关, 50ms采样一次, 50ms内的完成（开+关）会有可能被忽略
void TpUpdateSystemSwitchState(void)
{
	zy_st.ctrl_switch = GPIOReadSystemSwitchState() ? (zy_st.ctrl_switch | CTRL_HARD_SWITCH) : (zy_st.ctrl_switch & (~CTRL_HARD_SWITCH)); // 50ms 间隔天然去抖
}

// 取消高低温报警 level = 1 要取消上电前置条件(重新判断) 
void TgTemAlarmCancel(int level)
{
	if (level >= 1) {
		zy_st.power_up_6h = zy_st.temp_reach_region = 0;
	}
	if (CFG_DEVICE_TYPE == 760 && ((zy_st.alarm & ZQ_ALARM_H) || (zy_st.alarm & ZQ_ALARM_L))) { // 760 要求立刻恢复目标温度，这里借用last_disp_tem = ZY_TEM_INVALID的方式
		extern short last_disp_tem;
		last_disp_tem = ZY_TEM_INVALID;
	}
	zy_st.alarm_ad_timer = 0;
	zy_st.alarm &= (~(ZQ_ALARM_H | ZQ_ALARM_L));
}
// 判断高低温报警
void TgTemAlarm(int span_s)
{
	// 报警取消条件, 2. 若远程调节过设定温度或高/低温报警值, 3. 若本地进行了按键操作，相关模块实现
	// 报警取消条件 4, 传感器故障
	if (zy_st.alarm & ZQ_ALARM_SENSOR)
		goto TgTemAlarm_Cancel;
	// 报警取消条件 5, 远程关机、本地关机， 远程关机会重置高低温报警的触发条件, 特别是包括了上电前置条件。
	if ((zy_st.ctrl_switch & CTRL_ALL_SWITCH) != CTRL_ALL_SWITCH) {
		TgTemAlarmCancel(1);
		return;
	}
	// 报警取消条件 6, 化霜 Kg modified 202031229 客户要求：化霜优先级大于(中断)报警
	if((zy_st.comp_mode & COMP_MODE_DEFROST_MASK) || zy_st.defrost_lock_timer > 0)
		goto TgTemAlarm_Cancel;
	//// 报警取消条件 6, 门开，强制制冷
	//if(zy_st.defrost_state || (zy_st.alarm & ZQ_ALARM_DOOR_OPEN) || zy_st.comp_mode == COMP_MODE_FROCE)
	//	goto TgTemAlarm_Cancel;
	// 报警取消条件 8, 通电时间小于 AS 小时(akm 固定6小时)，并且实际温度没有达到过【TS-2，TS+2】区间
	if (CFG_DEVICE_TYPE == 1624 || CFG_DEVICE_TYPE == 1625 || CFG_DEVICE_TYPE == 760) {
		if (pm_ctrl.dm != 0 && zy_st.power_up_6h < TEM_ALARM_PRE_TIME)
			goto TgTemAlarm_Cancel;
		else if (pm_ctrl.dm == 0 && zy_st.temp_reach_region == 0 && zy_st.power_up_6h < TEM_ALARM_PRE_TIME)
			goto TgTemAlarm_Cancel;
	}
	else if ((CFG_DEVICE_TYPE/100) == 24326) {
		if (zy_st.temp_reach_region == 0 && zy_st.power_up_6h < (pm_ctrl.as*3600))
			goto TgTemAlarm_Cancel;
	}
	else {
		if (zy_st.temp_reach_region == 0 && zy_st.power_up_6h < TEM_ALARM_PRE_TIME)
			goto TgTemAlarm_Cancel;
	}

	// TODO 报警取消条件 9, 显示方式变化 -- task_console.c切换时候处理/还有远程修改该参数时候处理

	short TS = TcGetTS();
	static int spec_6_3_7_1_2_timer_1_minutes = 0; // 计时 spec 6.3.7.1-2 要求测量温度低于报警温度起码大于1分钟
	short ah = (pms_spec[pm_idx.ah].unit == PMU_DC) ? (TS + pm_ctrl.ah) : pm_ctrl.ah;	// 某些机型(比如915, 1198)pm_idx.ah是delta值，要在TS上叠加
	short al = (pms_spec[pm_idx.al].unit == PMU_DC) ? (TS - pm_ctrl.al) : pm_ctrl.al;	// 某些机型(比如915, 1198)pm_idx.ah是delta值，要在TS上叠加

	short PM_F6_limit = 0; // 冷藏低温报警值小于等于PM_F6_limit的情况下, 依据测量温度报警, 一般PM_F6_limit = 0
	if (CFG_DEVICE_TYPE == 1624) PM_F6_limit = 10; // 1624修正PM_F6_limit = 10（1℃）
	else if (zy_st.ctrl_mode & CTRL_MODE_FREEZE)  PM_F6_limit = -0x7fff; // 冷冻模式PM_F6_limit无效, 修正PM_F6_limit = -0x7fff
	
	if (pms_spec[pm_idx.al].unit == PMU_NX) PM_F6_limit = al = -0x7fff;		// 某些机型(比如870, 1001, 1198, 1004, 1026)不支持F6, 没有低温报警 
	short alarm_tem_h = zy_st.d_temp, alarm_tem_l = zy_st.d_temp;	// 高低温报警用显示温度判断，特例如下，注意有优先级
	if (pm_ctrl.dm == 2) { // 特例1： 显示2模式下: 
		if (CFG_DEVICE_TYPE == 1624 || CFG_DEVICE_TYPE == 1625) alarm_tem_h = alarm_tem_l = (zy_st.m_temp + pm_ctrl.c5); // 1624/1625等太古机型依赖测量温度判断
		else if (CFG_DEVICE_TYPE == 760) { // 760用特别修正温度判断
			if (zy_st.m_temp >= 0) alarm_tem_h = alarm_tem_l = zy_st.m_temp + pm_ctrl.c5;
			else if (zy_st.m_temp >= -100) alarm_tem_h = alarm_tem_l = zy_st.m_temp + pm_ctrl.c5 + 10;
			else if (zy_st.m_temp >= -200) alarm_tem_h = alarm_tem_l = zy_st.m_temp + pm_ctrl.c5 + 20;
			else if (zy_st.m_temp >= -300) alarm_tem_h = alarm_tem_l = zy_st.m_temp + pm_ctrl.c5 + 30;
			else if (zy_st.m_temp >= -400) alarm_tem_h = alarm_tem_l = zy_st.m_temp + pm_ctrl.c5 + 40;
			else alarm_tem_h = alarm_tem_l = zy_st.m_temp + pm_ctrl.c5 + 60;
		}
	}
	if (alarm_tem_h >= ah) { // 高温报警
		zy_st.alarm_ad_timer += span_s;
		if (zy_st.alarm & ZQ_ALARM_L) goto TgTemAlarm_Cancel; // 高低温突变, QA快速切换电阻箱才会，保护一下，先取消报警，下一轮会重新判断
		if(zy_st.alarm_ad_timer > pm_ctrl.ad * 60) zy_st.alarm |= ZQ_ALARM_H; // 报警取消条件 7, 报警延时有效时间内			
		return;
	}
	else if (pm_ctrl.al <= PM_F6_limit && zy_st.d_temp <= PM_F6_limit) { // 低温报警1：低温报警值小于等于0℃时：当显示温度等于最低显示温度值（0℃） 
		if (zy_st.alarm_ad_timer == 0) 	// init spec_6_3_7_1_2_timer_1_minutes
			spec_6_3_7_1_2_timer_1_minutes = 0;
		if (pm_ctrl.al <= PM_F6_limit) alarm_tem_l = zy_st.m_temp; // 特例2：低温小于特限后，改为用测量温度判断
		zy_st.alarm_ad_timer += span_s;	// spec 6.3.7.1-2 要求显示温度低于0, 就开始计时AD
		if (alarm_tem_l <= al) {
			if (zy_st.alarm & ZQ_ALARM_H) goto TgTemAlarm_Cancel; // 高低温突变, QA快速切换电阻箱才会，保护一下，先取消报警，下一轮会重新判断
			if (zy_st.alarm_ad_timer > pm_ctrl.ad * 60 && (zy_st.alarm_ad_timer - spec_6_3_7_1_2_timer_1_minutes) > 60) zy_st.alarm |= ZQ_ALARM_L; // 报警取消条件 7, 报警延时有效时间内， spec 6.3.7.1-2 要求测量温度低于报警温度起码大于1分钟
			return;
		}
		else spec_6_3_7_1_2_timer_1_minutes = zy_st.alarm_ad_timer;
	}
	else if (alarm_tem_l <= al) { // 低温报警
		zy_st.alarm_ad_timer += span_s;
		if (zy_st.alarm & ZQ_ALARM_H) goto TgTemAlarm_Cancel; // 高低温突变, QA快速切换电阻箱才会，保护一下，先取消报警，下一轮会重新判断
		if (zy_st.alarm_ad_timer > pm_ctrl.ad * 60) zy_st.alarm |= ZQ_ALARM_L; // 报警取消条件 7, 报警延时有效时间内			
		return;
	}
	else zy_st.alarm_ad_timer = 0;

	// 报警取消条件 1, 温度正常
TgTemAlarm_Cancel:
	TgTemAlarmCancel(0);
	return;
}

void TPUpdatePowState(int span_s)
{
	// 12v供电判断
	if (!PowRead12vState())
		zy_st.alarm |= ZQ_ALARM_POW;
	else
		zy_st.alarm &= (~ZQ_ALARM_POW);
	// 电池侦测
#if (ZQ_FUNC_BATTERY == 1)
	zy_st.vbat = BatteryUpdateState(span_s, zy_st.vbat);
	if (zy_st.vbat != NUM_INVALID_WORD) {
		zy_st.vbat = (short)(AdcGetVBat() * (147 + 510) / 510);
		if (pm_idx.f3 != ZQM_PM_IDX_NA) pm_ctrl.f3 = pms_spec[pm_idx.f3].val = GetVbatPercentage(zy_st.vbat);
	}
	else {
		if (pm_idx.f3 != ZQM_PM_IDX_NA) pm_ctrl.f3 = pms_spec[pm_idx.f3].val = -1;
	}
#endif
}

// be called every task period
void TgTask(uint32_t span_1s)
{
	short adc_calib = 0; // 记录当前adc粗调校正值

	if(zq_timer_50ms == 0) { // init
		TgTemAlarmCancel(1); // 重置报警状态
		PowMeterInit(); // 初始化功率计
	}
	if(zy_st.power_up_6h < TEM_ALARM_PRE_TIME) // 上电6小时计时
		zy_st.power_up_6h += span_1s;
	// ** ADC采样
	// 校准
	adc_calib = ADC_DataCalib_Rough();
	// ADC 采样参考电压
	AdcSamplingRef(adc_calib);
	// ADC 采样NTC1-温度探头
	AdcSamplingNtc1(adc_calib);
	// ADC 采样NTC2-温度探头
	if (ADC_CH_NTC2 != 0x80) // NTC2 有效
		AdcSamplingNtc2(adc_calib);
	// ADC 采样电压
	AdcSamplingVBat(adc_calib);
	// 更新电源/电池状态
	TPUpdatePowState(span_1s);
	//zy_st.vbat = GetMeasureVBat();
	// 更新温度状态
	GetMeasureTem();
	// 更新化霜传感器温度状态
	if (ADC_CH_NTC2 != 0x80) // NTC2 有效
		GetDefrostMeasureTem();
	// spec 6.3.16 检测系统开关状态
	TpUpdateSystemSwitchState();
	// spec 6.3.17 检测门状态 -- 1002，关机也要上报门状态，所以不判断zy_st.ctrl_state状态了
	if(CFG_DEVICE_TYPE == 1002) TpUpdateDoorState(span_1s);
	if (zy_st.ctrl_state == CTRL_STATE_NORMAL) {
		// spec 6.3.17 检测门状态 -- 其他机型关机就不用判断
		if(CFG_DEVICE_TYPE != 1002) TpUpdateDoorState(span_1s);
		// spec 6.3.15 人感检测
		TpUpdateHumanCountState();
		// 功率计
		PowMeterGather(&(zy_st.load_vol), &(zy_st.load_cur), &(zy_st.load_pow));
		// spec 6.3.7 高低温报警状态更新
		TgTemAlarm(span_1s);
	}
	else {
		if(CFG_DEVICE_TYPE != 1002) zy_st.door1_timer = 0; // Kg modify 20231214 补丁，防止门灯闪烁
	}


}
// 低功耗版本采样任务
void TgTask_LP(void)
{
	static unsigned int timer = 0;
	timer++;
	// 秒计时
	int span_1s = (timer % 20 == 0) ? 1 : 0;	// timer span = 1s, 约2480天溢出瞬间会有最大1s误差
	short adc_calib = 0; // 记录当前adc粗调校正值

	// ** ADC采样
	// 校准
	adc_calib = ADC_DataCalib_Rough();
	// ADC 采样参考电压
	AdcSamplingRef(adc_calib);
	// ADC 采样NTC1-温度探头
	AdcSamplingNtc1(adc_calib);
	// ADC 采样NTC2-温度探头
	if (ADC_CH_NTC2 != 0x80) // NTC2 有效
		AdcSamplingNtc2(adc_calib);
	// ADC 采样电压
	AdcSamplingVBat(adc_calib);
	// 更新电源/电池状态
	TPUpdatePowState(span_1s);
	//zy_st.vbat = GetMeasureVBat();
	// 更新温度状态
	GetMeasureTem();
	// spec 6.3.16 检测系统开关状态
	TpUpdateSystemSwitchState();
}
